package com.ray.test.proxy.asm;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.lang.reflect.Method;

/**
 * @author bo shen
 * @Description: asm aop method
 * @Class: AsmAopMethodAdapter
 * @Package com.ray.test.proxy.asm
 * @date 2019/12/20 11:13
 * @company <p>杭州传化陆鲸科技有限公司</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
public class AsmAopMethodAdapter extends MethodAdapter implements Opcodes {
    //max_stack至少需要能够容纳2个常量地址(监控方法使用)和1个exception地址
    private final static int EXCEPTION_STACK = 2 + 1;

    private Label try_catch_start,try_catch_end;

    private Method method;

    public AsmAopMethodAdapter(MethodVisitor mv, Method method) {
        super(mv);
        try_catch_start = new Label();
        try_catch_end = new Label();
        this.method = method;
    }

    public void visitCode() {
        mv.visitCode();
        mv.visitLabel(try_catch_start);
        mv.visitLdcInsn(method);
        mv.visitMethodInsn(INVOKESTATIC, "com/ray/test/proxy/asm/AsmHander",
                "before", "(Ljava/lang/reflect;)V");
    }

    public void visitInsn(int opcode){
        if(opcode >= IRETURN && opcode <= RETURN){
            mv.visitLdcInsn(method);
            mv.visitMethodInsn(INVOKESTATIC, "com/ray/test/proxy/asm/AsmHander","after", "(Ljava/lang/reflect;)V");
        }
        mv.visitInsn(opcode);
    }

    public void visitMaxs(int maxStack,int maxLocals){
        //保证max stack足够大
        mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals);
    }
}
